package uk.ac.nott.cs.g53dia.bee;

import java.util.ArrayList;
import java.util.List;

import meadow.MeadowWrapper;
import uk.ac.nott.cs.g53dia.Action;
import uk.ac.nott.cs.g53dia.ActionFailedException;
import uk.ac.nott.cs.g53dia.Bee;
import uk.ac.nott.cs.g53dia.BeeViewer;
import uk.ac.nott.cs.g53dia.Cell;
import uk.ac.nott.cs.g53dia.DeadBeeException;
import uk.ac.nott.cs.g53dia.Environment;
import utils.Constants;
import utils.ControlPanel;
import utils.Simulation;
import valueobj.GlobalState;


public class BeeSimulator extends Simulator {
  private List<Integer> eggsPerDay = new ArrayList<Integer>();
  private List<Integer> unusedEnergyPerDay = new ArrayList<Integer>();
  private int day = 0;

  @Override
  public void simulate() {
    setGlobalState(new GlobalState(getSwarm(), getEnv()));
    long endOfDay = Environment.DAY_LENGTH;
    int eggsLastTime = 0;

    // Start executing the bee
    while (Simulation.isStarted()) {
      while (!isPAUSED() && Simulation.isStarted() && getEnv().getTimestep() < (getDuration() * Environment.DAY_LENGTH)) {
        // Advance the environment timestep
        getEnv().tick();
        ControlPanel.getInstance().setTimestep(getEnv().getTimestep());
        // Update the GUI
        if (getBv() != null) {
          getBv().tick(getEnv());
        }
        // Get the current view of the bee
        for (Bee bee : getSwarm()) {
          Cell[][] view = getEnv().getView(bee.getPosition(), Bee.VIEW_RANGE);
          if (getMeadow() != null)
            getMeadow().updt(bee, view);
          // Let the bee choose an action
          Action action = bee.senseAndAct(view, getEnv().getTimestep());
          // Try and execute the action
          try {
            if (isPlaying()) {
              if (action == null) {
                Simulation.setStarted(false);
                break;
              }
            }
            action.execute(getEnv(), bee);
            if (isRecording())
              getRecorder().writeAction(action);
          } catch (DeadBeeException dbe) {
            if (Constants.DEBUG) {
              System.out.println("Bee has died!");
            }
            break;
          } catch (ActionFailedException afe) {
            System.err.println("Failed: " + afe.getMessage());
          } finally {
            getGlobalState().addInformation(bee, bee.getCells());
          }
        }
        if (getDelay() > 10) {
          try {
            Thread.sleep(getDelay());
          } catch (Exception e) {
          }
        }
        if (isRecording())
          getRecorder().append(
              getEnv().getTimestep() % Constants.RECORDER_DEBUG_STEP == 0 ? "#timestep=" + getEnv().getTimestep() : "");
        if (Simulation.getSettings().isGui() && getEnv().getTimestep() == Constants.STARTING_TIME + 1) {
          ControlPanel.getInstance().handlePause();
          MeadowWrapper.initialize("Meadow", 800, 800, Constants.GS_INITIAL_X, Constants.GS_INITIAL_Y, getGlobalState());
          setMeadow(MeadowWrapper.getInstance());
          getMeadow().setVisible(true);
        }
        if (getEnv().getTimestep() >= endOfDay) {
          day++;
          endOfDay += Environment.DAY_LENGTH;
          eggsPerDay.add(ControlPanel.getInstance().getEggs() - eggsLastTime);
          eggsLastTime = ControlPanel.getInstance().getEggs();
          unusedEnergyPerDay.add(ControlPanel.getInstance().getEnergy());
        }
        
        
//        if (getEnv().getTimestep() == 11000) {
//          ControllPanel.getInstance().handlePause();
//        }
      }
      if (getEnv().getTimestep() >= (getDuration() * Environment.DAY_LENGTH)) { // the end
        Simulation.setStarted(false);
      }
    }
    results();
    if (getBv() != null) {
      getBv().setVisible(false);
    }
  }

  @Override
  public void results() {
    System.out.println("----------------------------");
    int sum = 0;
    if (getSwarm() != null) {
      for (Bee bee : getSwarm()) {
        System.out.println("Bee " + bee.getId() + " has laid " + bee.getLaid() + " eggs.");
        sum += bee.getLaid();
      }
    }
    System.out.println("----------------------------");
    for (int i = 0; i < day; i++) {
      System.out.println("Eggs per day " + i + ": " + eggsPerDay.get(i));
      System.out.println("Unused energy per day " + i + ": " + unusedEnergyPerDay.get(i));
      System.out.println("----------------------------");
    }
    System.out.println("Total eggs laid: " + sum);
    System.out.println("Energy in nest: " + ControlPanel.getInstance().getEnergy());
  }

  @Override
  public void clean() {
    if (isRecording())
      getRecorder().close();
    if (isPlaying())
      getPlayer().close();
    setBv(null);
    setEnv(null);
    setSwarm(null);
  }

}
